import React from "react";

import {Menu} from 'antd';
import {withRouter} from "react-router";

import BaseComponent from "../../../../../../redare/components/BaseComponent";
import {WebPageMap} from "../../../../../../WebPageMap";

import {Page404, Page403, Page500} from "../../../common/Pages";
import Icon from "../../../../../../redare/components/common/Icon";
import Route from "../../../../../../redare/components/router/Route";
import CommonPresenter from "../../../../presenter/CommonPresenter";

class NavMenu extends BaseComponent {

    static defaultProps = {
        onRoutesReady: undefined
    };

    constructor(props) {
        super(props);
        this.presenter = new CommonPresenter(this);
        this.state.openMenus = [];
        this.state.activeMenu = [];
    }

    componentDidMount() {
        window.addEventListener('popstate', () => {
            this._initActiveMenu(false);
        });
        this._loadMenuList();
    }

    _loadMenuList() {
        this.showLoadingIndicator('加载中...');
        this.presenter.findUserMenu({}, (data) => {
            this._initMenuData(data);
            this.refreshState();
        });
    }

    _onMenuSelect(menu) {
        let {menuId, urlPath, componentWebPath} = menu;
        let _url = componentWebPath;
        if (urlPath) {
            _url = urlPath
        }
        if (!_url) {
            _url = window._ctxApi;
        }
        if (!_url) {
            _url = '/';
        }
        this.routePush(this.props.history, _url);
        this.setState({activeMenu: [`menu-${menuId}`]})
    }

    _onMenuClick(menu) {
        let {_url} = menu;
        let basename = this.getRouterBaseName() || '';
        if (!basename) {
            basename = '/';
        }
        let pathname = window.location.pathname;
        if (basename !== '' && basename !== '/') {
            pathname = pathname.replace(basename, '');
        }
        if (pathname === _url || pathname === _url + '/') {
            let {activeMenu} = this.state;
            if (!activeMenu || activeMenu.length === 0 || activeMenu[0] !== `menu-${menu.menuId}`) {
                this.setState({activeMenu: [`menu-${menu.menuId}`]})
            }
            return;
        }
        this._onMenuSelect(menu);
    }

    showLoadingIndicator(text) {
        this.showSpin(text);
    }

    closeLoadingIndicator() {
        this.closeSpin();
    }

    _wrapperMenu(menus) {
        let _menus = [];
        if (!(menus instanceof Array)) {
            return _menus;
        }
        for (let i = 0; i < menus.length; i++) {
            let m = menus[i];
            let {name, menuId, urlPath, componentWebPath, iconCls} = m;
            let _url = componentWebPath;
            if (urlPath) {
                _url = urlPath
            }
            if (!_url) {
                _url = '';
            }
            if (m.children && m.children.length > 0) {
                _menus.push(
                    <Menu.SubMenu key={`menu-${menuId}`}
                                  title={<span><Icon name={iconCls} color="#FFF"/><span>{name}</span></span>}>
                        {
                            this._wrapperMenu(m.children)
                        }
                    </Menu.SubMenu>
                );
            } else {
                _menus.push(
                    <Menu.Item key={`menu-${menuId}`} data={m}>
                        <Icon name={iconCls} color="#FFF"/>
                        <span>{name}</span>
                    </Menu.Item>
                );
            }
        }
        return _menus;
    }

    _findFirstMenu(menu, openMenus, activeMenu) {
        let {menuId, children} = menu;
        if (children && children.length > 0) {
            openMenus.push(`menu-${menuId}`);
            return this._findFirstMenu(children[0], openMenus, activeMenu);
        } else {
            activeMenu.push(`menu-${menuId}`);
            return menu;
        }
    }

    _findMenuByPath(pathname, menus, openMenus) {
        let create = !openMenus;
        for (let i = 0; i < menus.length; i++) {
            if (create) {
                openMenus = [];
            }
            let m = menus[i];
            let {menuId, children, urlPath, componentWebPath} = m;
            let url = componentWebPath;
            if (urlPath) {
                url = urlPath;
            }
            if (!url) {
                url = '';
            }

            if (children && children.length > 0) {
                openMenus.push(`menu-${menuId}`);
                let obj = this._findMenuByPath(pathname, children, openMenus);
                if (obj) {
                    return obj;
                }
            } else {
                if (pathname === url || pathname === url + '/') {
                    return {menu: m, openMenus};
                }
            }
        }
    }

    _initActiveMenu(push) {
        if (!this._menus || this._menus.length === 0) {
            return;
        }
        let basename = this.getRouterBaseName() || '';
        if (!basename) {
            basename = '/';
        }
        let pathname = window.location.pathname;
        if (pathname === basename || pathname === basename + '/') {
            //第一个菜单
            let openMenus = [];
            let activeMenu = [];
            let menu = this._findFirstMenu(this._menus[0], openMenus, activeMenu);
            if (push) {
                this._onMenuSelect(menu);
            }
            this.setState({openMenus, activeMenu});
        } else {
            //查找菜单
            if (basename !== '' && basename !== '/') {
                pathname = pathname.replace(basename, '');
            }
            let activeMenu = [];
            let {menu, openMenus = []} = this._findMenuByPath(pathname, this._menus) || {};
            if (menu) {//查找是否有匹配的菜单
                activeMenu.push(`menu-${menu.menuId}`);
                if (push) {
                    this._onMenuSelect(menu);
                }
                this.setState({openMenus, activeMenu});
            } else {//查找是否有匹配的页面
                let _parentMenu;
                for (let i = 0; i < this._pages.length; i++) {
                    if (_parentMenu) {
                        break;
                    }
                    let p = this._pages[i];
                    let {urlPathPatterns, parentMenu} = p;
                    for (let j = 0; j < urlPathPatterns.length; j++) {
                        if (urlPathPatterns[j].test(pathname)) {
                            _parentMenu = parentMenu;
                            break;
                        }
                    }
                }
                if (_parentMenu) {
                    let {menu, openMenus = []} = this._findMenuByPath(_parentMenu._url, this._menus) || {};
                    if (menu) {
                        activeMenu.push(`menu-${menu.menuId}`);
                    }
                    this.setState({openMenus, activeMenu});
                } else {
                    this.setState({openMenus: [], activeMenu});
                }
            }
        }
    }

    _initMenuData(menuList) {
        let routers = [];
        let _menuMap = {};
        let _rootMenuList = [];
        let _refPageList = [];
        if ((menuList instanceof Array) && menuList.length > 0) {
            for (let i = 0; i < menuList.length; i++) {
                let m = menuList[i];
                let {menuId, parentMenuId, hasPermission, urlPath, componentWebPath, componentClassId, enabled, refPage} = m;
                let _url = componentWebPath;
                if (urlPath) {
                    _url = urlPath
                }
                m._url = _url;
                if (refPage) {
                    m.urlPathPatterns = [];
                    if (_url) {
                        let _urls = _url.split(',');
                        _urls.forEach(_tmpUrl => {
                            let _tmpUrls = _tmpUrl.split('/');
                            let _tmpUrls2 = [];
                            _tmpUrls.forEach((_p) => {
                                if (_p) {
                                    if (_p.indexOf(':') === 0) {
                                        _tmpUrls2.push('[^/]+');
                                    } else {
                                        _tmpUrls2.push(_p);
                                    }
                                }
                            });
                            m.urlPathPatterns.push(
                                new RegExp(`^/${_tmpUrls2.join('/')}[/]?$`)
                            );
                        });
                    }
                    _refPageList.push(m);
                }
                if (enabled && hasPermission && !refPage) {
                    _menuMap[menuId] = m;
                    if (!parentMenuId) {
                        _rootMenuList.push(m);
                    }
                }
                //构造路由
                if (urlPath || componentWebPath) {
                    let Component;
                    if (componentClassId) {
                        Component = WebPageMap[componentClassId];
                    }
                    let routeUrls = [];
                    if (urlPath) {
                        routeUrls.push(urlPath);
                    }
                    if (componentWebPath) {
                        routeUrls.push(...componentWebPath.split(','));
                    }

                    if (Component && enabled) {
                        if (hasPermission) {
                            routers.push(
                                <Route key={`route-${menuId}`} path={routeUrls} exact={true} component={Component}
                                       cache={!refPage}/>
                            );
                        } else {
                            routers.push(
                                <Route key={`route-${menuId}`} path={routeUrls} exact={true}>
                                    <Page403/>
                                </Route>
                            );
                        }
                    } else {
                        if (componentClassId) {
                            routers.push(
                                <Route key={`route-${menuId}`} path={routeUrls} exact={true}>
                                    <Page500 title={`WebPageMap.js文件中未找到id[${componentClassId}]对应的组件`}/>
                                </Route>
                            );
                        } else {
                            routers.push(
                                <Route key={`route-${menuId}`} path={routeUrls} exact={true}>
                                    <Page500 title="路径缺少组件关联配置"/>
                                </Route>
                            );
                        }
                    }
                }
            }
            for (let i = 0; i < menuList.length; i++) {
                let m = menuList[i];
                let {parentMenuId, enabled, hasPermission, refPage} = m;
                if (!enabled || !parentMenuId || !hasPermission || refPage) {
                    continue;
                }
                let pM = _menuMap[parentMenuId];
                if (!pM) {
                    continue;
                }
                if (!(pM.children instanceof Array)) {
                    pM.children = [];
                }
                pM.children.push(m);
            }
            for (let i = 0; i < _refPageList.length; i++) {
                let _page = _refPageList[i];
                let {parentMenuId} = _page;
                _page.parentMenu = _menuMap[parentMenuId];
            }
        }
        routers.push(
            <Route key='route-404' cache={true}>
                <Page404/>
            </Route>
        );
        this._menus = _rootMenuList;
        this._pages = _refPageList;
        this._routers = routers;
        this._init = true;

        this._initActiveMenu(true);
        if (this.props.onRoutesReady) {
            this.props.onRoutesReady(this._routers);
        }
    }

    _renderMenu() {
        if (!this._init) {
            return null;
        }
        return this._wrapperMenu(this._menus);
    }

    render() {
        let menus = this._renderMenu();
        return this.renderSpin(
            <Menu className="nav-menu"
                  theme="dark"
                  mode="inline"
                  onClick={({item}) => this._onMenuClick(item.props.data || {})}
                  openKeys={this.state.openMenus}
                  onOpenChange={(openMenus) => this.setState({openMenus})}
                  selectedKeys={this.state.activeMenu}>
                {
                    menus
                }
            </Menu>
        );
    }
}

export default withRouter(NavMenu);
